﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Xml;
//MicroDesigner
using Jc.MicroDesigner.Management;

namespace Jc.MicroDesigner.Objects
{
    /// <summary>
    /// Сложный элемент, включающий в себя схему
    /// является генератором для генерации сигналов во внутренней схеме
    /// </summary>
    public sealed class CompositeElement : CircuitElement, ISignalGenerator
    {
        private List<CompositeGate> _Gates = new List<CompositeGate>();
        private ObjectManager _InnerScheme = null;

        //фильтр для генерации начального сигнала
        private List<PIN> NotConnectedInputs = new List<PIN>();

        private CompositeElement(string Name) : base(Name) { }

        /// <summary>
        /// Создать составной элемент
        /// </summary>
        /// <param name="manager">Схема</param>
        /// <param name="config">Файл-конфигурации</param>
        public CompositeElement(ObjectManager manager, string config)
            : base(manager, config)
        {
            // Создаём фильтр с неподключёнными входными пинами для подачи на них Initial Signal
            List<BaseElement> _Elements = _InnerScheme.Elements;

            for (int i = 0; i < _Elements.Count; i++)
            {
                if (!(_Elements[i] is Node) && !(_Elements[i] is Wire) &&
                    (_Elements[i] is CircuitElement) && !(_Elements[i] is ISignalGenerator))
                {
                    CircuitElement ce = _Elements[i] as CircuitElement;
                    //Просматриваем пины
                    foreach (PIN p in ce.PINs)
                    {
                        if ((p.Type == PINType.In) && (p.FriendPIN == null))
                            NotConnectedInputs.Add(p);
                    }
                }
            }

            manager.Generators.Add(this);
        }

        /// <summary>
        /// Загрузка внутреннего устройства интегральной схемы
        /// </summary>
        /// <param name="additionals"></param>
        protected override void LoadConfigProps(XmlNode additionals)
        {
            // 1. Загрузим внутренню структуру из <scheme>
            XmlNode scheme_node = additionals.ChildNodes[0];
            _InnerScheme = SchemeSerializer.LoadSchemeFromNode(scheme_node);
            // 2. Подключим шлюзы из ветки <gates>
            XmlNode gates_node = additionals.ChildNodes[1];
            foreach (XmlNode uno_gate in gates_node.ChildNodes)
            {
                string our_pin = uno_gate.Attributes["interface_pin"].Value;
                string elem_name = uno_gate.Attributes["element"].Value;
                string elem_pin = uno_gate.Attributes["element_pin"].Value;

                PIN our = GetPINByName(our_pin);
                BaseElement elem = _InnerScheme.SearchElementByName(elem_name);
                if (elem != null)
                {
                    PIN p = (elem as CircuitElement).GetPINByName(elem_pin);
                    _Gates.Add(new CompositeGate(p, our));
                }
            }
        }

        /// <summary>
        /// Обновить состояние схемы внутри
        /// </summary>
        public override void Refresh()
        {
            _InnerScheme.Refresh();
            _InnerScheme.InitialSignal = _Manager.InitialSignal;
            base.Refresh();
        }

        /// <summary>
        /// Переопределяем выполнение работы
        /// </summary>
        /// <returns></returns>
        public override bool PerformAction()
        {
            bool elements_result = false;
            if (_InnerScheme != null)
                for (int i = 0; i < _InnerScheme.Elements.Count; i++)
                {
                    if (_InnerScheme.Elements[i] is CircuitElement)
                        elements_result = elements_result | (_InnerScheme.Elements[i] as CircuitElement).PerformAction();
                }
            return elements_result;
        }

        /// <summary>
        /// Переопределяем отправку сигналов
        /// </summary>
        /// <returns></returns>
        public override bool SendData()
        {
            bool elements_result = false;
            if (_InnerScheme != null)
                for (int i = 0; i < _InnerScheme.Elements.Count; i++)
                {
                    if (_InnerScheme.Elements[i] is CircuitElement)
                        elements_result = elements_result | (_InnerScheme.Elements[i] as CircuitElement).SendData();
                }
            return elements_result;
        }

        /// <summary>
        /// Обернуть схему в элемент
        /// </summary>
        /// <param name="scheme">Схема сложного элемента</param>
        /// <param name="view">Информация по пинам и шлюзам</param>
        /// <returns>Составной элемент</returns>
        public static CompositeElement Create(ObjectManager scheme, CompositeView view)
        {
            CompositeElement element = new CompositeElement(view.Name);
            //Присваиваем свойства
            element._InnerScheme = scheme;
            element.DrawOptions.ImageFile = view.ImgPath;
            element.Description = view.Description;

            foreach (GateView gate in view.Views)
            {
                //Создаём пин
                PIN p = element.CreateSpecialPIN();
                p.Type = gate.PinType;
                PIN.PINImage pimg = p.DrawOptions as PIN.PINImage;

                pimg.Left = gate.Left;
                pimg.Top = gate.Top;
                pimg.Width = gate.Width;
                pimg.Height = gate.Height;

                pimg.BindingPoint = new System.Drawing.Point(gate.BindX, gate.BindY);

                element.PINs.Add(p);

                //Создаём шлюз
                if (gate.InnerPIN.SelectedPin != null)
                {
                    element.Gates.Add(new CompositeGate(gate.InnerPIN.SelectedPin, p));
                }
            }
            return element;
        }

        /// <summary>
        /// Шлюзы
        /// </summary>
        public List<CompositeGate> Gates
        {
            get
            {
                return _Gates;
            }
        }

        /// <summary>
        /// Внутреннее устройство элемента
        /// </summary>
        public ObjectManager InnerScheme
        {
            get { return _InnerScheme; }
        }

        #region ISignalGenerator Members

        /// <summary>
        /// Сигналы генератора
        /// </summary>
        public SignalContainer SignalsCollection
        {
            get { return null; }
        }

        /// <summary>
        /// Сгенерировать сигнал
        /// </summary>
        /// <param name="time">Время</param>
        /// <param name="tact">Такт</param>
        public void GenerateSignal(int time, int tact)
        {
            //генерируем новые сигналы
            for (int gi = 0; gi < _InnerScheme.Generators.Count; gi++)
                _InnerScheme.Generators[gi].GenerateSignal(time, tact);
            //генерируем сигналы на отключенных входных пинах 
            foreach (PIN in_pin in NotConnectedInputs)
                in_pin.Recieve(_InnerScheme.InitialSignal);
        }

        /// <summary>
        /// Флаг редактирования
        /// </summary>
        public bool Editable
        {
            get { return false; }
        }

        #endregion
    }
}